import defineProperty from "./utils.js"

class Store {
  static _Vue = null;

  constructor(options = {}) {
    const {
      state = {},
      getters = {},
      mutations = {},
      actions = {},
      plugins = [] } = options;

    this.getters = Object.create(null);
    this.state = Store._Vue.observable(state);

    for (const callback in getters) {
      // defineProperty(this, getters, callback);
      Object.defineProperty(this.getters, callback, {
        get() {
          return getters[callback](state);
        },
        enumerable: true
      });
    }
    this.mutations = mutations;
    this.actions = actions;
    this.plugins = plugins;
    this.mutation = null;
  }

  commit(type, payload) {
    if (type && this.mutations[type]) {
      this.mutation = { type, payload };
      this.mutations[type](this.state, payload);
    }
    for (const callback of this.plugins) {
      callback(this);
    }
    this.mutation = null;
  }

  dispatch(type, payload) {
    if (type && this.actions[type]) {
      this.actions[type](this, payload);
    }
  }

  subscribe(callback, options) {
    if ("function" === typeof callback) {
      callback(this.mutation, this.state);
    }
  }
}

function install(Vue) {
  Store._Vue = Vue;

  Vue.mixin({
    beforeCreate() {
      const options = this.$options;
      if (options.store) {
        // Vue实例执行逻辑
        Store._Vue.prototype.$store = options.store;
        // this.$store = options.store;
      } else if (options.parent && options.parent.$store) {
        // Vue组件执行逻辑
        this.$store = options.parent.$store;
      }
    },
  })
}

export default {
  Store,
  install
}
